home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / OTLLCTest / OTLLCTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-13  |  36.0 KB  |  1,405 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        OTLLCTest.c
  3.  
  4.     Contains:    Simple app write or receive 8022 Ethernet packets using a multicast address
  5.  
  6.     Written by:    Rich Kubota
  7.  
  8.     Copyright:    © 1993-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.     01/98    added threshold timer to control how often WNE gets called.  
  12.     01/98    fixed sample so that you can send in raw mode and receive in regular mode or vice versa
  13.                  and things work.  
  14.             Fixed problem that when setting the max data packet size to 1500 bytes and
  15.                 are sending data in regular mode, adjust the unitdata.data.len field to
  16.                 account for the fact that the endpoint will insert the LLC header and the
  17.                 SNAP header.  For raw mode, this is not an issue.
  18.             Added feature to 1. allow the program to be re-used without having to quit
  19.             2. ask user for the drivername to use e.g. 'enet0, 'enet1', etc.,
  20.     01/98    modified the sample to use the revised NegotiateRawModeOption code which returns
  21.                 the template type.  The Mentat template driver returns an additional 24 bytes
  22.                 of info at the beginning of the raw data packet.
  23.     01/98    modified DoBind so that one can use either a regular LLC to SNAP endpoint.
  24.     10/97    fixed bug in OT 8022 module which prevented more than 1483 data bytes from being
  25.                 sent in raw mode.  Requires OT 1.3 to send > 1483 data bytes with endpoint
  26.                 in rawdata mode.
  27.     
  28.  
  29.     This program implements both a sender and receiver such that both sides
  30.     open an 802.2 Ethernet endpoint. The user can then select whether to run the 
  31.     program as a sender or receiver. If implemented as a receiver, the endpoint
  32.     is bound, and the multicast option is turned on. The receiver waits in a 
  33.     spin loop for a specified period of time before quitting.  The receiver will process
  34.     all incoming ethernet packets destined to the endpoint for the specified
  35.     protocol.  Upon receipt, the program checks to see whether the packet was sequential
  36.     to the previous packet.  A collection of global counter maintains the number of
  37.     inOrder, outOfOrder packets, and the number of packets reads resulting in an error,
  38.     plus the number of packets which come in back to back while in the handler.
  39.     
  40.     Note the this sample turns on the rawmode option so that the handler will be passed the
  41.     14 byte 802.2 header.
  42.     Also note that the sender may also implement the rawmode option so that it can also
  43.     fill in the header bytes itself.  If this is done, then the buffer needs to 
  44.     be enlarged to include these additional bytes.  These additional bytes will not affect
  45.     the maximum tsdu size since the tsdu size is the i-frame limit and does not include
  46.     the header size.
  47.     
  48.     The sender process, sends 10005 x 1500 byte packets as fast as possible.  The user 
  49.     can select to to turn on AckSends mode where the packet is handed to OT and not
  50.     released until OT sends the information to the lower layer. 
  51.     
  52.     
  53.  
  54. */
  55.  
  56. #include <stdio.h>
  57. #include <Types.h>
  58. #include <Memory.h>
  59. #include <Resources.h>
  60. #include <Events.h>
  61. #include <OpenTransport.h>            // open transport files            
  62. #include <OpenTptLinks.h>
  63. #include <OpenTptAppleTalk.h>
  64. #include <OpenTptConfig.h>
  65. #include <Time.h>
  66. #include <Errors.h>
  67. #include <String.h>
  68. #include "OTLLCTest.h"
  69. #include "NegotiateRawModeSample.h"
  70.  
  71. // Comment out the following line if synchronous sends desired.
  72. #define __ASYNCSEND__    1
  73.  
  74. //-----------------------------------------------------------------------------------------
  75. // Globals
  76. //-----------------------------------------------------------------------------------------
  77.  
  78. EndpointRef        gEndpoint;
  79. OSStatus        gstatus;
  80. UInt32            gFlags;
  81. UInt32            gNumBack, gNumFore;
  82. UInt32            gPacketsRead;
  83. UInt32            gBackToBackPackets;    
  84. UInt32            gInOrder;
  85. UInt32            gOutOfOrder;
  86. UInt32            gCounter;
  87. UInt32            gNumDataEvents;
  88. UInt32            gReadErrors;
  89. UInt32            gTemplateType;
  90. UInt32            gNumMemErrs;
  91. UInt32            gTimerThreshold;
  92. UInt8            *gBuffer;
  93. UInt8            *gDummyBuffer;
  94. struct T8022Address     gAddr;
  95. UInt8            gmcAddr[k48BitAddrLength] = {MCASTADDR0,MCASTADDR1,MCASTADDR2,MCASTADDR3,MCASTADDR4,MCASTADDR5};
  96. PacketBuffer    gPacket;
  97. UInt8            gFlag1;
  98. Boolean            gDone;
  99. Boolean            gAbort;
  100. //-----------------------------------------------------------------------------------------
  101. // Prototypes
  102. //-----------------------------------------------------------------------------------------
  103. extern OSStatus OTSetMemoryLimits(size_t growSize, size_t mazSize);
  104. OSStatus         DoBind();
  105. OSStatus         DoAddMulticast(EndpointRef ep, unsigned char *mcAddr);
  106. OSStatus        DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr);
  107. void             WriteApplIntro(void);
  108. UInt32             GetYesNoOption(void);
  109. UInt32             GetUserOption(void);
  110. Boolean         CanDoMDATAMode(EndpointRef ep);
  111. void            DoOTLLCWriteTest(void);
  112. Boolean         DoSendPacket(EndpointRef ep);
  113. void            DoOTLLCReadTest(void);
  114. OSStatus         DoReadPacket(EndpointRef ep, UInt8 *mainBuffer);
  115. pascal void     LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie);
  116. void             CallWNE(void);
  117. void            MyIdle(void);
  118. void             DoValueBreak(long value, const char* message);
  119. void             GetDriverName(char *name);
  120. void             SetTimerThreshold(void);
  121. void             PrintAppleTalkPortName(void);
  122. void             ListEnetDrivers(void);
  123.  
  124.  
  125. /*******************************************************************************
  126. ** DoBindENET
  127. ********************************************************************************/
  128.  
  129. OSStatus DoBind(void)
  130. {
  131.     OSStatus        osstatus;
  132.     TBind            requestInfo;
  133.     TBind            responseInfo;
  134.     UInt32            i;
  135.     
  136.     gAddr.fAddrFamily = AF_8022;
  137.     
  138.     for (i = 0; i < k48BitAddrLength; i++)
  139.         gAddr.fHWAddr[i] = 0x00;
  140.         
  141.     gAddr.fSAP = TESTSAP;
  142.     
  143.     if (TESTSAP == 0xAA)
  144.     {    
  145.         // set SNAP fields;
  146.         
  147.         gAddr.fSNAP[0] = MYSNAP0;        // set these values in the interface file OTLLCTest.h
  148.         gAddr.fSNAP[1] = MYSNAP1;
  149.         gAddr.fSNAP[2] = MYSNAP2;
  150.         gAddr.fSNAP[3] = MYSNAP3;
  151.         gAddr.fSNAP[4] = MYSNAP4;
  152.         
  153.         requestInfo.addr.len = k8022SNAPAddressLength;        
  154.     }
  155.     else
  156.     {
  157.         requestInfo.addr.len = k8022BasicAddressLength;        
  158.     }
  159.  
  160.         
  161.         // finish bind information
  162.     requestInfo.addr.buf = (UInt8 *)&gAddr;
  163.  
  164.     requestInfo.addr.maxlen = 0;            
  165.     requestInfo.qlen = 0;
  166.     
  167.     responseInfo.addr.buf = (UInt8 *)&gAddr;
  168.     responseInfo.addr.len = 0;        
  169.     responseInfo.addr.maxlen = k8022SNAPAddressLength;
  170.     responseInfo.qlen = 0;
  171.     
  172.     
  173.     
  174.     osstatus = OTBind(gEndpoint, &requestInfo, &responseInfo);
  175.     if (osstatus == kOTNoError)
  176.         SetEPBoundFlag(gFlags);
  177.         
  178.     return osstatus;
  179. }
  180.  
  181.  
  182.  
  183. /*******************************************************************************
  184. ** DoAddMulticast
  185. ********************************************************************************/
  186.  
  187. OSStatus DoAddMulticast(EndpointRef ep, unsigned char *mcAddr)
  188. {
  189.     OSStatus    osstatus = noErr;
  190.     TOptMgmt    req;
  191.     UInt8        reqOpt[64];        
  192.     
  193.     req.opt.buf    = reqOpt;
  194.     req.flags    = T_NEGOTIATE;
  195.     
  196.     ((TOption*)reqOpt)->level    = LNK_TPI;
  197.     ((TOption*)reqOpt)->name    = OPT_ADDMCAST;
  198.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  199.     ((TOption*)reqOpt)->status    = 0;
  200.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  201.                 
  202.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  203.     req.opt.maxlen = sizeof(reqOpt);
  204.                 
  205.     if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
  206.         fprintf(stderr, "DoAddMulticast - OptionManagement Returned %d\n", osstatus);
  207.     else
  208.     {
  209.         if (((TOption*)reqOpt)->status != T_SUCCESS)
  210.         
  211.         {
  212.             fprintf(stderr, "DoAddMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
  213.             osstatus = -1;
  214.         }
  215.         else
  216.         {
  217.             fprintf(stderr, "DoAddMulticast - was successful\n");
  218.             SetMCastActiveFlag(gFlags);
  219.         }
  220.     }
  221.     return osstatus;
  222. }
  223.  
  224.  
  225. /*******************************************************************************
  226. ** DoRemoveMulticast
  227. ********************************************************************************/
  228.  
  229. OSStatus DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr)
  230. {
  231.     OSStatus    osstatus = noErr;
  232.     TOptMgmt    req;
  233.     UInt8        reqOpt[64];        
  234.     
  235.     req.opt.buf    = reqOpt;
  236.     req.flags    = T_NEGOTIATE;
  237.     
  238.     ((TOption*)reqOpt)->level    = LNK_TPI;
  239.     ((TOption*)reqOpt)->name    = OPT_DELMCAST;
  240.     ((TOption*)reqOpt)->status    = 0;
  241.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  242.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  243.                     
  244.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  245.     req.opt.maxlen    = sizeof(reqOpt);
  246.     
  247.     if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
  248.         fprintf(stderr, "\nDoRemoveMulticast failed - OptionManagement Returned %d.", osstatus);
  249.     else
  250.     { 
  251.         if (((TOption*)reqOpt)->status != T_SUCCESS)
  252.         {
  253.             fprintf(stderr, "nDoRemoveMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
  254.             osstatus = -1;
  255.         }
  256.         else
  257.         {
  258.             fprintf(stderr, "nDoRemoveMulticast - was successful\n");
  259.             SetMCastActiveFlag(gFlags);
  260.         }
  261.     }
  262.  
  263.     return osstatus;
  264. }
  265.  
  266. void WriteApplIntro(void)
  267. {
  268.     fprintf(stderr, "\nEthernet 802.2 LLC Test program v1.0\n");
  269.     fprintf(stderr, "\nThis test application sets the system");
  270.     fprintf(stderr, "\ninto send or receive mode.\n");
  271.     fprintf(stderr, "\nThe send portion of this program sets the Ethernet");
  272.     fprintf(stderr, "\ndriver to use a multicast address, then sends 10000");
  273.     fprintf(stderr, "\n- 1500 byte packets out the wire.\n");
  274.     fprintf(stderr, "\nThe receive portion of this program sets the Ethernet");
  275.     fprintf(stderr, "\ndriver to use a multicast address, then waits for the");
  276.     fprintf(stderr, "\n10000 - 1500 byte packets or times out after 30 seconds.\n");
  277.     fprintf(stderr, "\n\nUsing SAP address %d.\n", TESTSAP);
  278.     
  279. }
  280.  
  281. UInt32 GetYesNoOption(void)
  282. {
  283.     UInt32    result;
  284.     char    selection[32];
  285.     Boolean    done;
  286.     
  287.     fprintf(stdout, "\n    Enter Y - To accept option");
  288.     fprintf(stdout, "\n    Enter N - To decline option");
  289.     fprintf(stdout, "\n    Enter Q - To quit");
  290.     fprintf(stdout, "\nYour selection -> ");
  291.     fflush(stdout);
  292.     done = false;
  293.  
  294.     do
  295.     {
  296.         scanf("%s", selection);
  297.         switch (selection[0])
  298.         {
  299.             case 'y':
  300.             case 'Y':
  301.                 result = kAcceptOption;
  302.                 done = true;
  303.                 break;
  304.             
  305.             case 'n':
  306.             case 'N':
  307.                 result = kDeclineOption;
  308.                 done = true;
  309.                 break;
  310.  
  311.             case 'q':
  312.             case 'Q':
  313.                 result = kQuitTest;
  314.                 done = true;
  315.                 break;
  316.                 
  317.             default:
  318.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  319.                 fflush(stdout);
  320.                 break;
  321.  
  322.         }
  323.     } while (!done);
  324.     
  325.     fflush (stdout);
  326.     return result;
  327. }
  328.  
  329.  
  330. UInt32 GetUserOption(void)
  331. {
  332.     UInt32    result;
  333.     char    selection[32];
  334.     Boolean    done;
  335.     
  336.     fprintf(stdout, "\nSelect the type of test to run");
  337.     fprintf(stdout, "\nMake sure that the receive program is already launched");
  338.     fprintf(stdout, "\n    Enter S - Send test packets");
  339.     fprintf(stdout, "\n    Enter R - Receive test packets");
  340.     fprintf(stdout, "\n    Enter q - quit");
  341.     fprintf(stdout, "\nYour selection -> ");
  342.     fflush(stdout);
  343.     done = false;
  344.  
  345.     do
  346.     {
  347.         scanf("%s", selection);
  348.         switch (selection[0])
  349.         {
  350.             case 'r':
  351.             case 'R':
  352.                 result = kReceiveTest;
  353.                 done = true;
  354.                 break;
  355.             
  356.             case 's':
  357.             case 'S':
  358.                 result = kSendTest;
  359.                 done = true;
  360.                 break;
  361.  
  362.             case 'q':
  363.             case 'Q':
  364.                 result = kQuitTest;
  365.                 done = true;
  366.                 break;
  367.                 
  368.             default:
  369.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  370.                 fflush(stdout);
  371.                 break;
  372.  
  373.         }
  374.     } while (!done);
  375.     
  376.     fflush (stdout);
  377.     return result;
  378. }
  379.  
  380. /*
  381.     CanDoMDATAMode gets the endpoint info and checks whether the T_CAN_SUPPORT_MDATA bit is
  382.     set in the endpoint info flag field and returns true if so, false otherwise.
  383. */
  384. Boolean CanDoMDATAMode(EndpointRef ep)
  385. {
  386.     TEndpointInfo    info;
  387.     OSStatus        err;
  388.     Boolean            result;
  389.     
  390.     err = OTGetEndpointInfo(ep, &info);
  391.     if (err != kOTNoError)
  392.         result = false;
  393.     else if (info.flags & T_CAN_SUPPORT_MDATA)
  394.         result = true;        // this also means that the src addr info is in the info record
  395.     else
  396.         result = false;
  397.  
  398.     return result;
  399. }
  400.  
  401.  
  402. void DoOTLLCWriteTest(void)
  403. {
  404.     OSStatus    osstatus;
  405.     TUnitData    unitdata;
  406.     UInt32        numMemErrs, last250;
  407.     UInt32        lastFlowErrPacketNum;
  408.     UInt32        n, timer, selection;
  409.     time_t        t1, t2, t3;
  410.     UInt16        rawModeOffset = 0;
  411.     Boolean        callDoIdle;
  412.     
  413.     
  414.     osstatus = DoBind();
  415.     
  416.     OTMemzero(&gPacket, sizeof(gPacket));        // zero out the global packet buffer structure
  417.  
  418.     if (TstUseAckSendsFlag(gFlags))
  419.     {
  420.         osstatus = OTAckSends(gEndpoint);
  421.         if (osstatus != kOTNoError)
  422.         {
  423.             fprintf (stdout, "\n Error turning AckSends on - error %ld", osstatus);
  424.             ClrUseAckSendsFlag(gFlags);
  425.             gNumFore = gNumBack = 0;
  426.         }
  427.     }
  428.  
  429.     if (TstUseRawModeFlag(gFlags))
  430.     {
  431.         if (CanDoMDATAMode(gEndpoint) && (DATASIZE <= 1500))
  432.         {
  433.             osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
  434.             if (osstatus == kOTNoError)
  435.             {
  436.                 SetRawModeFlag(gFlags);
  437.                     /* if rawmode is on then we want to offset the data
  438.                     * an additional 17 bytes and set the header info
  439.                     * ourselves.
  440.                     * note that 17 bytes constitutes the 6 byte dAddr, 6 byte sAddr
  441.                     * 2 byte length field, 1 byte ssap, 1 byte dsap and 1 byte control byte
  442.                     
  443.                     * Note that even if the DSAP is not 0xAA, we go ahead and stuff the 5 bytes
  444.                     * following the control byte, with whatever SNAP values have been defined.
  445.                     */
  446.                 gPacket.rawModeOffset = 17;
  447.                     // check is we are doing SNAP
  448.                 if (TESTSAP == 0xAA)
  449.                     gPacket.rawModeOffset += 5;
  450.                 fprintf (stdout, "\n raw mode option enabled");
  451.             }
  452.             else
  453.             {
  454.                     // if the option failed, then we don't use it'
  455.                 fprintf (stdout, "\nError negotiating raw mode option");
  456.                     // reset the status result.
  457.                 osstatus = kOTNoError;
  458.             }
  459.         }
  460.         else
  461.             fprintf (stdout, "\nYou need a later version of OT which supports the MDataMode option");
  462.     }
  463.  
  464. #if __ASYNCSEND__
  465.     if (osstatus == kOTNoError)
  466.     {
  467.         osstatus = OTSetAsynchronous(gEndpoint);
  468.         if (osstatus != kOTNoError) 
  469.         {
  470.             fprintf(stderr, "\n\nError making endpoint asynchronous!");
  471.             fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
  472.         }
  473.     }    // now ready to handle async events
  474. #endif        
  475.  
  476.     if (osstatus == kOTNoError)
  477.     {
  478.             // set up the first 18 bytes past the control byte for non SNAP LLC endpoint or
  479.             // past the SNAP header for a SNAP endpoint, so that we can recognize it 
  480.         OTStrCopy((char*)&gPacket.data[gPacket.rawModeOffset], "begin data section");
  481.  
  482.             // set up some specific bytes in the data buffer that begins at the same point
  483.             // relative to the LLC or SNAP header
  484.         gPacket.data[DATAOFFSET     + gPacket.rawModeOffset] = 0;
  485.         gPacket.data[DATAOFFSET + 1 + gPacket.rawModeOffset] = 0;
  486.         OTStrCopy((char*)&gPacket.data[DATAOFFSET+2 + gPacket.rawModeOffset], "end of data section");
  487.         
  488.         gPacket.unitdata.udata.buf = (UInt8*)gPacket.data;
  489.     
  490.         if (TstRawModeFlag(gFlags))
  491.             gPacket.unitdata.udata.len = DATASIZE + 14;
  492.         else
  493.         {
  494.                 // the DATASIZE setting represents the total size of the packet
  495.                 // following the ethernet header.  If we are not doing a rawmode send
  496.                 // then we need to account for the fact that part of the data area
  497.                 // will be used by OT to place the SSAP, DSAP, and Control byte.  If
  498.                 // we are sending a SNAP packet, then we have to account for the 5
  499.                 // additional bytes of the SNAP header.  Otherwise if the unidata.data.len
  500.                 // field were set to the full size of 1500, the packet would not be sent
  501.                 // since OT would think it was trying to send a 1503 or 1508 byte 
  502.                 // ethernet packet (not including the ethernet header).
  503.                 
  504.                 // By doing this, we can process the packet using either a raw data or
  505.                 // regular ethernet endpoint as the receiver.
  506.                 
  507.             if (TESTSAP == 0xAA)
  508.                 gPacket.unitdata.udata.len = DATASIZE - 8;
  509.             else
  510.                 gPacket.unitdata.udata.len = DATASIZE - 3;
  511.         }
  512.             
  513.         gPacket.unitdata.opt.len = 0;
  514.         gPacket.unitdata.opt.buf = NULL;
  515.  
  516.         if (TstRawModeFlag(gFlags) == false)
  517.         {
  518.                 // set up the destination addresss
  519.             gPacket.dAddr.fAddrFamily = AF_8022;
  520.             
  521.             gPacket.dAddr.fHWAddr[0] = MCASTADDR0;
  522.             gPacket.dAddr.fHWAddr[1] = MCASTADDR1;
  523.             gPacket.dAddr.fHWAddr[2] = MCASTADDR2;
  524.             gPacket.dAddr.fHWAddr[3] = MCASTADDR3;
  525.             gPacket.dAddr.fHWAddr[4] = MCASTADDR4;
  526.             gPacket.dAddr.fHWAddr[5] = MCASTADDR5;
  527.                 
  528.             gPacket.dAddr.fSAP = TESTSAP;
  529.             
  530.             gPacket.unitdata.addr.buf = (UInt8*)&gPacket.dAddr;
  531.             if (TESTSAP == 0xAA)
  532.             {
  533.                 gPacket.dAddr.fSNAP[0] = MYSNAP0;
  534.                 gPacket.dAddr.fSNAP[1] = MYSNAP1;
  535.                 gPacket.dAddr.fSNAP[2] = MYSNAP2;
  536.                 gPacket.dAddr.fSNAP[3] = MYSNAP3;
  537.                 gPacket.dAddr.fSNAP[4] = MYSNAP4;
  538.         
  539.                 gPacket.unitdata.addr.len = k8022SNAPAddressLength;
  540.             }
  541.             else
  542.                 gPacket.unitdata.addr.len = k8022BasicAddressLength;
  543.  
  544.         }
  545.         else
  546.         {
  547.                 // set up for a rawmode send data call
  548.             gPacket.data[0] = MCASTADDR0;
  549.             gPacket.data[1] = MCASTADDR1;
  550.             gPacket.data[2] = MCASTADDR2;
  551.             gPacket.data[3] = MCASTADDR3;
  552.             gPacket.data[4] = MCASTADDR4;
  553.             gPacket.data[5] = MCASTADDR5;
  554.                 // set the packet len field
  555.             gPacket.data[12] = DATASIZE >> 8;
  556.             gPacket.data[13] = DATASIZE & 0xFF;
  557.                 // set the dsap, ssap, and control byte fields.
  558.             gPacket.data[14] = TESTSAP;            // set DSAP
  559.             gPacket.data[15] = TESTSAP;            // set SSAP
  560.             gPacket.data[16] = 0x03;            // set control byte
  561.             
  562.             if (TESTSAP == 0xAA)
  563.             {
  564.                     // set up the SNAP Addr
  565.                 gPacket.data[17] = MYSNAP0;
  566.                 gPacket.data[18] = MYSNAP1;
  567.                 gPacket.data[19] = MYSNAP2;
  568.                 gPacket.data[20] = MYSNAP3;
  569.                 gPacket.data[21] = MYSNAP4;
  570.             }
  571.         
  572.             gPacket.unitdata.addr.buf = nil;    
  573.                                         // don't want to set the destination address since we've already 
  574.                                         // done so in the data
  575.                                         
  576.                                         // the following line is required for OT 1.2 and greater
  577.                                         // where there is a bug with how OT deals with mentat template
  578.                                         // based drivers, such that in rawmode, the total packet size - 
  579.                                         // header + data is limited to 1500 bytes.  By using the following
  580.                                         // line, OT will not check for this limitation and will go ahead
  581.                                         // and send an MDATA message.
  582.  
  583.             gPacket.unitdata.addr.len = 0xFFFFFFFFL;        
  584.                                         // magic constant for M_DATA mode
  585.                         
  586.         }
  587.  
  588.  
  589.         ClrFlowClrFlag(gFlags);        // clear the flag that indicates that a T_GODATA event occurred
  590.                                     // we do this because a race condition might occur when we make the
  591.                                     // the OTSndUData call, a flowerr may occur, but get cleared by the time
  592.                                     // we actually check the osstatus field
  593.  
  594.         fprintf (stdout, "\n starting write of %ld llc packets of %ld bytes\n", (long)SENDCOUNT, (long)DATASIZE);
  595.         fflush(stdout);
  596.         t1 = clock ();
  597.         
  598.         gDone = false;
  599.         gPacket.i = 0;
  600.         numMemErrs = last250 = 0;
  601.         lastFlowErrPacketNum = 0;
  602.         timer = 0;
  603.         callDoIdle = false;
  604.         
  605.             // set the flag that will tell us to send a packet at system task time so that
  606.             // we can send the initial packet
  607.         SetSysTaskSendFlag(gFlags);
  608.         
  609.         while (!gDone && !gAbort)
  610.         {            
  611.             if (TstSysTaskSendFlag(gFlags))
  612.             {
  613.                 if (DoSendPacket(gEndpoint) == true)
  614.                 {
  615.                     gNumFore++;
  616.                 }
  617.             }
  618.  
  619.             if (gNumMemErrs)
  620.             {
  621.                 if (numMemErrs != gNumMemErrs)
  622.                 {
  623.                     numMemErrs = gNumMemErrs;
  624.  
  625.                     fprintf(stderr, "\nkENOMEMErr %ld.", gPacket.i);
  626.                     callDoIdle = true;
  627.                 }
  628.             }
  629.                         
  630. #if 0    // the following code really affect the performance of this tool
  631.         // and can consume over 95 percent of the processing time of this tool
  632.         // on a fast system.
  633.             n = gPacket.i / 250;
  634.             if (n > last250)
  635.             {
  636.                 fprintf(stderr, "%d ", n * 250);
  637.                 fflush(stderr);
  638.                 last250 = n;
  639.  
  640.             }
  641. #endif
  642.                         
  643.             timer++;
  644.             if (timer > gTimerThreshold)
  645.             {
  646.                 callDoIdle = true;
  647.             }
  648.                     
  649.             if (gPacket.lastFlowErrPacketNum != 0)
  650.             {
  651.                 if (lastFlowErrPacketNum != gPacket.lastFlowErrPacketNum)
  652.                 {
  653.                     fprintf(stderr, "\nflow error occurred while sending packet %d.", gPacket.lastFlowErrPacketNum);
  654.                     lastFlowErrPacketNum = gPacket.lastFlowErrPacketNum;
  655.                 }
  656.             }
  657.             
  658.                 // check if we are flow controlled or if it's time to call WNE and call it.
  659.             if ((callDoIdle == true) || TstFlowErrFlag(gFlags))
  660.             {
  661.                 CallWNE();
  662.                 callDoIdle = false;
  663.                 timer = 0;
  664.             }
  665.             
  666.         }    // end while loop sending data
  667.  
  668.         fflush(stderr);
  669.                 
  670.         t2 = clock();
  671.         t3 = t2 - t1;
  672.         fprintf (stdout, "\nCompleted sending %ld llc packets.", (long)gPacket.i);
  673.         fprintf (stdout, "\nTime start = %ld, time end = %ld, time taken %ld seconds.",
  674.                      t1, t2, (long)t3/CLOCKS_PER_SEC);
  675.         fprintf (stdout, "\nPackets per second = %ld, bytes/second = %ld.",
  676.                      ((long)gPacket.i*CLOCKS_PER_SEC)/t3, ((long)gPacket.i*DATASIZE*CLOCKS_PER_SEC)/t3);
  677.         
  678.         fprintf (stdout, "\n Press the mouse to unbind the endpoint");
  679.         
  680.         if (TstUseAckSendsFlag(gFlags) == true)
  681.         {
  682.             fprintf (stdout, "\nThe number of packets sent from the while loop - %ld", gNumFore);
  683.             fprintf (stdout, "\nThe number of packets sent from the handler - %ld", gNumBack);
  684.         }
  685.         
  686.         fflush(stdout);
  687.  
  688.         while (!Button())
  689.             MyIdle();
  690.                         
  691.         
  692.     }    // end if bind successful
  693.  
  694. #if __ASYNCSEND__    
  695.     if (TstEPBoundFlag(gFlags))
  696.     {
  697.         OTSetSynchronous(gEndpoint);
  698.         OTUnbind(gEndpoint);
  699.     }
  700. #endif
  701.  
  702. }
  703.  
  704. Boolean DoSendPacket(EndpointRef ep)
  705. {
  706.     OSStatus        osstatus;
  707.     Boolean            didEnter;
  708.  
  709.         // check to see if we have already entered this function.
  710.         // we only want to enter into it once whether at system task time or from the
  711.         // handler
  712.     if (OTAtomicSetBit(&gFlag1, kInSendPacketBit))
  713.         return false;
  714.     
  715.         // call OTenterNotifier so that the notifier is not entered while we are in the following
  716.         // section of code. In this way we protect ourselves from race conditions that could 
  717.         // happen - for example if a flowErr occured, but was cleared before we set the flowErr
  718.         // flag, this would be a problem since we would never receive notification that flow
  719.         // control was lifted.
  720.         
  721.     didEnter = OTEnterNotifier(ep);
  722.         
  723.     if (gDone == false)
  724.     {
  725.             // we already assume that the packet is ready to send
  726.         osstatus = OTSndUData(gEndpoint, &gPacket.unitdata);
  727.     }
  728.     
  729.     switch (osstatus)
  730.     {
  731.         case kENOMEMErr:
  732.             gNumMemErrs++;
  733.             break;
  734.             
  735.         case kOTNoError:    // send was successful
  736.             gPacket.i++;
  737.                             
  738.             if (gPacket.i >= SENDCOUNT)
  739.                 gDone = true;
  740.             else
  741.             {
  742.                     // increment the counter in the packet
  743.                 gPacket.data[DATAOFFSET+0+gPacket.rawModeOffset] = gPacket.i >> 8;
  744.                 gPacket.data[DATAOFFSET+1+gPacket.rawModeOffset] = gPacket.i;
  745.                     
  746.             }                
  747.             break;
  748.         
  749.         case kOTFlowErr:
  750.             SetFlowErrFlag(gFlags);            // a T_GODATA did not just come in
  751.             ClrSysTaskSendFlag(gFlags);        // clear the flag that we check to send a packet
  752.             gPacket.lastFlowErrPacketNum = gPacket.i;    // save the packet number on which the flow err occured
  753.             break;
  754.         
  755.         default:
  756.             DoValueBreak(osstatus, "Unknown error occurred in DoSendPacket #;");
  757.             gDone = true;
  758.             ClrSysTaskSendFlag(gFlags);
  759.             break;
  760.     }
  761.     
  762.     if (didEnter == true)
  763.          OTLeaveNotifier(ep);
  764.     
  765.     OTAtomicClearBit(&gFlag1, kInSendPacketBit);
  766.     return true;
  767. }
  768.         
  769. void DoOTLLCReadTest(void)
  770. {
  771.     OSStatus    osstatus;
  772.     long        timer;
  773.     
  774.     gBuffer = (UInt8*)NewPtr(DATASIZE + 2* DATASLOP);    // allocate the data buffer + some slop
  775.     if (gBuffer)
  776.         osstatus = DoBind();
  777.     else
  778.     {
  779.         osstatus = memFullErr;
  780.         return;
  781.     }
  782.  
  783.     gBackToBackPackets = 0;
  784.     gInOrder = 0;
  785.     gOutOfOrder = 0;
  786.     gCounter = 0;
  787.     gPacketsRead = 0;
  788.     gNumDataEvents = 0;
  789.     gReadErrors = 0;
  790.     gNumMemErrs = 0;
  791.     gDone = false;
  792.     
  793.     if (osstatus == kOTNoError)
  794.     {
  795.         osstatus = DoAddMulticast(gEndpoint, gmcAddr);
  796.     }
  797.     
  798.     if (osstatus == kOTNoError)
  799.     {
  800.         if (TstUseRawModeFlag(gFlags))
  801.         {
  802.             osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
  803.             if (osstatus == kOTNoError)
  804.             {
  805.                 SetRawModeFlag(gFlags);
  806.             }
  807.             else
  808.             {
  809.                     // if the option failed, then we don't use it'
  810.                 fprintf (stdout, "\nError negotiating raw mode option");
  811.                     // reset the status result.
  812.                 osstatus = kOTNoError;
  813.             }
  814.         }
  815.     }
  816.     
  817. #ifdef __ASYNCSEND__
  818.     if (osstatus == kOTNoError)
  819.     {
  820.         osstatus = OTSetAsynchronous(gEndpoint);
  821.         if (osstatus != kOTNoError) 
  822.         {
  823.             fprintf(stderr, "\n\nError making endpoint asynchronous!");
  824.             fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
  825.         }
  826.     }    // now ready to handle async events
  827. #endif
  828.         
  829.     if (osstatus == kOTNoError)
  830.     {
  831.         gAbort = false;
  832.         SetWantDataFlag(gFlags);
  833.                 
  834.         fprintf (stdout, "\nStarting Read test - will terminate in %d seconds", TIMEOUT);
  835.         fprintf (stdout, "\nor as soon as the trigger packet is received.");
  836.         fprintf (stdout, "\nYou may use Command-Q to quit the program entirely.");
  837.         fprintf (stdout, "\nYou may also use Command-A to terminate this test.\n");
  838.         fprintf (stdout, "\nStarting Read");
  839.         fflush(stdout);
  840.         
  841.         timer = TickCount() + TIMEOUT * 60;
  842.             // loop until timer is less than TickCount or until the endtime value gets set
  843.         
  844.         while ((timer > TickCount()) && (gDone == false) && (gAbort == false))
  845.         {
  846.                 // allow the user to exit the timer loop by 
  847.             CallWNE();
  848.         }
  849.  
  850.         
  851.         
  852.     }
  853.     
  854.     OTSetSynchronous(gEndpoint);
  855.         
  856.     if (TstMCastActiveFlag(gFlags))
  857.         DoRemoveMulticast(gEndpoint, gmcAddr);
  858.         
  859.     
  860.     if (osstatus == kOTNoError)
  861.     {
  862.         fprintf (stdout, "\n\nBufferReadCount = %ld", gPacketsRead);
  863.         fprintf (stdout, "\nInOrder = %ld\n", gInOrder);
  864.         fprintf (stdout, "\nOutofOrder = %ld\n", gOutOfOrder);
  865.         fprintf (stdout, "\nlast packet read was = %ld\n", gCounter);
  866.         fprintf (stdout, "\nNumber of data events was = %ld\n", gNumDataEvents);
  867.         fprintf (stdout, "\nNumber of read errors was = %ld\n", gReadErrors);
  868.         fprintf (stdout, "\nNumber of back to back packets was = %ld\n", gBackToBackPackets);
  869.         fflush(stdout);
  870.     }
  871.  
  872.     if (TstEPBoundFlag(gFlags))
  873.         OTUnbind(gEndpoint);
  874.  
  875.     if (gBuffer)
  876.         DisposePtr((Ptr)gBuffer);
  877.     
  878. }
  879.  
  880. OSStatus DoReadPacket(EndpointRef ep, UInt8 *mainBuffer)
  881. {
  882.     TUnitData    unitdata;
  883.     struct T8022Address    dAddr;
  884.     OTFlags        otFlags;
  885.     OSStatus    result, tempResult;
  886.     
  887.     unitdata.addr.maxlen = sizeof(dAddr);
  888.     unitdata.addr.buf = (UInt8*)&dAddr;
  889.     unitdata.udata.buf = mainBuffer;
  890.     unitdata.udata.maxlen = DATASIZE + DATASLOP;
  891.     unitdata.opt.maxlen = 0;
  892.     
  893.     result = OTRcvUData(ep, &unitdata, &otFlags);
  894.     return result;
  895. }
  896.  
  897. pascal void LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie)
  898. {
  899.     OSStatus    osstatus;
  900.     UInt8        *bufferToUse;
  901.     UInt32        lcounter, offset;
  902.     Boolean        firstTimeFlag;
  903.     
  904.     gstatus = result;
  905.     switch (event)
  906.     {
  907.         case T_MEMORYRELEASED:
  908.             if (DoSendPacket(gEndpoint) == false)
  909.                 SetSysTaskSendFlag(gFlags);
  910.             else
  911.             {
  912.                 ClrSysTaskSendFlag(gFlags);
  913.                 gNumBack++;
  914.             }
  915.             break;
  916.  
  917.         case T_OPTMGMTCOMPLETE:
  918.             ClrWaitOptMgmtFlag(gFlags);
  919.             break;
  920.             
  921.         case T_BINDCOMPLETE:
  922.             ClrStillBindFlag(gFlags);
  923.             break;
  924.         
  925.         case T_UNBINDCOMPLETE:
  926.             break;
  927.         
  928.         case T_GODATA:
  929.             SetFlowClrFlag(gFlags);    // indicate that the flow data problem has now cleared.
  930.             SetSysTaskSendFlag(gFlags);
  931.             break;
  932.         
  933.         case T_DATA:
  934.             gNumDataEvents++;
  935.             if (TstWantDataFlag(gFlags))
  936.                 bufferToUse = gBuffer;
  937.             else
  938.                 bufferToUse = gDummyBuffer;
  939.                 
  940.                 // initialize variables as we enter while loop
  941.             osstatus = kOTNoError;
  942.             firstTimeFlag = true;
  943.             
  944.             while ((osstatus == kOTNoError) && (!gDone))
  945.             {
  946.                 osstatus = DoReadPacket(gEndpoint, bufferToUse);
  947.                 
  948.                 if (firstTimeFlag == true)    
  949.                         // this is the first time through this loop 
  950.                         // for this call to the handler
  951.                     firstTimeFlag = false;
  952.                 else
  953.                         // increment the counter to indicate that there was a packet to
  954.                         // handle after reading the previous packet
  955.                     gBackToBackPackets++;
  956.                     
  957.                 if (osstatus != kOTNoDataErr)
  958.                 {
  959.                     if (osstatus < 0)
  960.                         gReadErrors++;
  961.                     else
  962.                         gPacketsRead++;
  963.                 }
  964.                     
  965.                 if (TstWantDataFlag(gFlags) && (osstatus == kOTNoError))
  966.                 {
  967.                     if (TstRawModeFlag(gFlags))
  968.                     {
  969.                             // if rawmode is on then we want to account for
  970.                             // the additional 17 bytes which will be at the
  971.                             // beginning of the packet.
  972.                         offset = 17;
  973.                         if (TESTSAP == 0xAA)
  974.                         {
  975.                             offset += 5;        // account for the SNAP header
  976.                         }
  977.                         
  978.                             // check if the template is a mentat template and 
  979.                             // adjust the offset to account for the additional
  980.                             // bytes that the template prepends to the ethernet
  981.                             // packet.
  982.                         if (gTemplateType == kMentatTemplate)
  983.                             offset += sizeof(dl_recv_status_t);
  984.                     }
  985.                     else
  986.                         offset = 0;
  987.                     
  988.                     lcounter = gBuffer[DATAOFFSET + offset +0] << 8;
  989.                     lcounter |= gBuffer[DATAOFFSET + offset +1];
  990.                     if (lcounter >= TRIGGEREND)
  991.                     {
  992.                         gDone = true;        // we can bail now.
  993.                     }
  994.                     else
  995.                     {
  996.                         if (lcounter == gCounter)
  997.                             gInOrder++;
  998.                         else
  999.                             gOutOfOrder++;
  1000.                         
  1001.                         gCounter = lcounter + 1;    // prepare gCounter for next incoming packet to compare
  1002.                     }
  1003.                 }
  1004.             }
  1005.             break;
  1006.             
  1007.         default:
  1008.             DoValueBreak(event, "Unknown event  occurred #           ;g");
  1009.             break;
  1010.             
  1011.         
  1012.     }    /* end switch on event */
  1013. }
  1014.  
  1015. /*******************************************************************************
  1016. ** CallWNE is implemented to call WaitNextEvent to check for the Command-Q key
  1017. ** sequence.  When this happens, then the gdone flag is set to true
  1018. ********************************************************************************/
  1019.  
  1020. void CallWNE(void)
  1021. {
  1022.     EventRecord     event;
  1023.     char            key;
  1024.     
  1025.     if (!WaitNextEvent(everyEvent, &event, 15, nil))
  1026.         event.what = nullEvent;
  1027.             
  1028.     switch (event.what)
  1029.     {
  1030.  
  1031.  
  1032.         case nullEvent:
  1033.         case mouseDown:
  1034.         case activateEvt:
  1035.         case updateEvt:
  1036.         case kHighLevelEvent:
  1037.         case osEvt:
  1038.         case diskEvt:
  1039.             break;
  1040.  
  1041.         case autoKey:
  1042.         case keyDown:
  1043.             key = event.message & charCodeMask;
  1044.             switch (key)
  1045.             {
  1046.                 case 'q':
  1047.                 case 'Q':
  1048.                     if (event.modifiers & cmdKey)
  1049.                     gDone = true;
  1050.                     break;
  1051.                     
  1052.                 case 'a':
  1053.                 case 'A':
  1054.                     if (event.modifiers & cmdKey)
  1055.                     gAbort = true;
  1056.                     break;
  1057.             }
  1058.             break;
  1059.  
  1060.     }
  1061.     
  1062. }
  1063.  
  1064. void MyIdle(void)
  1065. {
  1066.     EventRecord        event;
  1067.     OSErr            err;
  1068.     
  1069.     err = WaitNextEvent(everyEvent, &event, 15 + gNumMemErrs * 5, nil);
  1070. }
  1071.  
  1072. main (void)
  1073. {
  1074.     OSStatus    osstatus = noErr;
  1075.     UInt32        selection;
  1076.     char        drvrname[64];
  1077.     Boolean        done = false;
  1078.     
  1079.     WriteApplIntro();
  1080.     gFlags = 0;
  1081.     if (osstatus = InitOpenTransport())
  1082.     {
  1083.         fprintf(stderr, "\n\nOpen Transport is not installed!\n");
  1084.         fprintf(stderr, "\nBye Bye.\n");
  1085.     }
  1086.     else
  1087.     {
  1088.         SetOTActiveFlag(gFlags);    // indicate that OT is active
  1089.  
  1090.         gDummyBuffer = (UInt8*)NewPtr(DATASIZE + 2 * DATASLOP);
  1091.         if (gDummyBuffer == NULL)
  1092.             osstatus = memFullErr;
  1093.     }
  1094.     
  1095.     PrintAppleTalkPortName();
  1096.  
  1097.     while (done == false)
  1098.     {
  1099.         osstatus = OTSetMemoryLimits(10240000, 0);
  1100.         if (osstatus != kOTNoError)
  1101.         {
  1102.             fprintf(stderr, "\n OTSetMemoryLimits returned %d\n", osstatus);
  1103.             osstatus = kOTNoError;
  1104.         }
  1105.                 
  1106.         if (osstatus != kOTNoError)
  1107.         {
  1108.             done = true;
  1109.             break;
  1110.         }
  1111.         
  1112.         ListEnetDrivers();
  1113.         GetDriverName(drvrname);
  1114.         
  1115.             // open the default ethernet endpoint
  1116.         gEndpoint = OTOpenEndpoint(OTCreateConfiguration(drvrname), (OTOpenFlags)NULL, NULL, &osstatus);
  1117.         if (osstatus != kOTNoError)
  1118.         {
  1119.             fprintf(stderr, "\n\nError opening Ethernet endpoint!");
  1120.             fprintf(stderr, "\nOTOpenEndpoint returned %d\n", osstatus);
  1121.             fprintf(stderr, "\nBye Bye.\n");
  1122.             done = true;
  1123.         }
  1124.         else
  1125.             SetEPActiveFlag(gFlags);    // indicate that the endpoint is opened
  1126.     
  1127.         if (osstatus == kOTNoError)
  1128.         {
  1129.             osstatus = OTInstallNotifier(gEndpoint, LLCEventHandler, NULL);
  1130.             if (osstatus != kOTNoError)
  1131.             {
  1132.                 fprintf(stderr, "\n\nError installing notifier!");
  1133.                 fprintf(stderr, "\nOTInstallNotifier returned %d\n", osstatus);
  1134.             }
  1135.         }    // now ready to handle async events
  1136.     
  1137.         if (osstatus == kOTNoError)
  1138.         {
  1139.                 // ask whether to use the rawmode option or not
  1140.             fprintf(stdout, "\nDo you want to use the raw mode option?");
  1141.             selection = GetYesNoOption();
  1142.             if (selection == kQuitTest)
  1143.             {
  1144.                 fprintf(stderr, "\n\nBye-Bye!");
  1145.                 osstatus = -1;
  1146.                 done = true;
  1147.             }
  1148.             else if (selection == kAcceptOption)
  1149.                 SetUseRawModeFlag(gFlags);
  1150.             else if (selection == kDeclineOption)
  1151.                 ClrUseRawModeFlag(gFlags);
  1152.             
  1153.         }
  1154.     
  1155.         if (osstatus == kOTNoError)
  1156.         {
  1157.                 
  1158.                 // what does the user want to do
  1159.             selection = GetUserOption();
  1160.             
  1161.             switch (selection)
  1162.             {
  1163.                 case kSendTest:
  1164.                     fprintf(stdout, "\nDo you want to turn on AckSends?");
  1165.                     selection = GetYesNoOption();
  1166.                     if (selection == kQuitTest)
  1167.                     {
  1168.                         fprintf(stderr, "\n\nBye-Bye!");
  1169.                         done = true;
  1170.                         break;
  1171.                     }
  1172.                     else if (selection == kAcceptOption)
  1173.                     {
  1174.                         SetUseAckSendsFlag(gFlags);
  1175.                     }
  1176.                     else if (selection == kDeclineOption)
  1177.                     {
  1178.                         ClrUseAckSendsFlag(gFlags);
  1179.                         SetTimerThreshold();
  1180.                     }
  1181.  
  1182.                         // pause until the user clicks the mouse button
  1183.                     fprintf(stderr, "Click Mouse to start test\n");
  1184.                     while (!Button());
  1185.                     DoOTLLCWriteTest();
  1186.                     break;
  1187.                 
  1188.                 case kReceiveTest:
  1189.                         // pause until the user clicks the mouse button
  1190.                     fprintf(stderr, "\n\nClick Mouse to start test\n");
  1191.                     while (!Button());
  1192.  
  1193.                     DoOTLLCReadTest();
  1194.                     break;
  1195.                 
  1196.                 case kQuitTest:
  1197.                 default:
  1198.                     fprintf(stderr, "\n\nBye-Bye!");
  1199.                     done = true;
  1200.                     break;
  1201.             }
  1202.         }
  1203.             
  1204.         if (TstEPActiveFlag(gFlags))
  1205.         {
  1206.                 // force endpoint to be synchronous
  1207.             OTSetSynchronous(gEndpoint);
  1208.             OTCloseProvider(gEndpoint);
  1209.         }
  1210.         
  1211.         if (done == false)
  1212.         {
  1213.             fprintf(stdout, "\n\nDo you want to repeat the test?");
  1214.             selection = GetYesNoOption();
  1215.  
  1216.             if (selection != kAcceptOption)
  1217.                 done = true;
  1218.         }
  1219.     }
  1220.     
  1221.     if (gDummyBuffer)
  1222.         DisposePtr((Ptr)gDummyBuffer);
  1223.     
  1224.     OTSetMemoryLimits(0, 0);
  1225.         
  1226.     if (TstOTActiveFlag(gFlags))
  1227.         CloseOpenTransport();
  1228.     
  1229.     fprintf(stderr, "\nProgram ended");
  1230. }
  1231.  
  1232. void DoValueBreak(long value, const char* message)
  1233. {
  1234.     static short    sDoErrorBreak = 0;
  1235.  
  1236.     {
  1237.         Str255    s,
  1238.                 n = "\p";
  1239.  
  1240.         s[0] = strlen(message);
  1241.         BlockMoveData(message,&s[1],s[0]);
  1242.         if (value < 0)
  1243.         {
  1244.             s[0] += 1;
  1245.             s[s[0]] = '-';
  1246.             value = -value;
  1247.         }
  1248.         while (value)
  1249.         {
  1250.             if (n[0])
  1251.                 BlockMoveData(&n[1],&n[2],n[0]);
  1252.             n[0]++;
  1253.             n[1] = 48 + (value % 10);
  1254.             value /= 10;
  1255.         }
  1256.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1257.         s[0] += n[0];
  1258.  
  1259.         sDoErrorBreak++;
  1260.         {
  1261.             short    cnt = sDoErrorBreak;
  1262.  
  1263.             s[0]++;
  1264.             s[s[0]] = ',';
  1265.             s[0]++;
  1266.             s[s[0]] = ' ';
  1267.             n[0] = 0;
  1268.             while (cnt)
  1269.             {
  1270.                 if (n[0])
  1271.                     BlockMoveData(&n[1],&n[2],n[0]);
  1272.                 n[0]++;
  1273.                 n[1] = 48 + (cnt % 10);
  1274.                 cnt /= 10;
  1275.             }
  1276.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1277.             s[0] += n[0];
  1278.         }
  1279.         DebugStr(s);
  1280.     }
  1281. }
  1282.  
  1283. void GetDriverName(char *name)
  1284. {
  1285.         fprintf(stdout, "\nEnter the driver name to use");
  1286.         fprintf(stdout, "\nEnter an invalid driver name to quit");
  1287.         fprintf(stdout, "\n : ");
  1288.         while (true)
  1289.         {
  1290.             gets(name);
  1291.             if (*name != 0)
  1292.                 break;
  1293.         }
  1294. }
  1295.  
  1296. void SetTimerThreshold(void)
  1297. {
  1298.     char    chr, str[256];
  1299.     size_t    len, i;
  1300.     Boolean    done = false;
  1301.     
  1302.     while (done == false)
  1303.     {
  1304.         fprintf(stdout, "\n Enter the timer threshold");
  1305.         fprintf(stdout, "\n This is the number of times that the write loop loops before calling");
  1306.         fprintf(stdout, "\n WaitNextEvent. Enter a value of 10000 to never call WNE.");
  1307.         fprintf(stdout, "\n Enter a value of 100 to call WNE every 100 packets.\n");
  1308.         while (true)
  1309.         {
  1310.             gets(str);
  1311.             if (*str != 0)
  1312.                 break;
  1313.         }
  1314.         
  1315.         gTimerThreshold = 0;
  1316.         len = strlen(str);
  1317.         
  1318.         for (i = 0; i < len; i++)
  1319.         {
  1320.             chr = str[i];
  1321.             if ((chr >= '0') && (chr <= '9'))
  1322.                 gTimerThreshold = gTimerThreshold*10 + chr - '0';
  1323.         }
  1324.         
  1325.         if (gTimerThreshold != 0)
  1326.         {
  1327.             done = true;
  1328.             fprintf(stdout, "\n The timer threshold is set at %ld\n\n", gTimerThreshold);
  1329.             fflush(stdout);
  1330.         }
  1331.     }
  1332. }
  1333.  
  1334. /*
  1335.     The following routine prints the name of the port currently being used by AppleTalk
  1336.     If AppleTalk is using Ethernet, then the fPortName field could be used in the 
  1337.     OpenEndpoint call to open an ethernet endpoint on the same hardware port as AppleTalk
  1338. */
  1339. void PrintAppleTalkPortName(void)
  1340. {
  1341.     ATSvcRef            atref;
  1342.     OTOpenFlags            oflag;
  1343.     OSStatus            err;
  1344.     OTPortRef            portref;
  1345.     OTPortRecord        portrecord;
  1346.     TEndpointInfo        info;
  1347.     
  1348.     atref = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, &info, &err);
  1349.     
  1350.     if (err == kOTNoError)
  1351.     {
  1352.         portref = OTGetProviderPortRef(atref);
  1353.         if (portref != nil)
  1354.         {
  1355.             if (OTFindPortByRef(&portrecord, portref) == true)
  1356.             {
  1357. //                fprintf(stderr, "\n Appletalk port name is %s", portrecord.fPortName);
  1358.                 portref = portrecord.fChildPorts[0];
  1359.                 if (OTFindPortByRef(&portrecord, portref) == true)
  1360.                     fprintf(stdout, "\n Appletalk child port name is %s", portrecord.fPortName);
  1361.                 else
  1362.                     fprintf(stdout, "\n Appletalk child port record could not be found using PortRef %lX", portref);
  1363.             }
  1364.             else
  1365.                 fprintf(stdout, "\n Appletalk port record could not be found using PortRef %lX", portref);
  1366.         }
  1367.         else
  1368.             fprintf(stdout, "\n OTGetProviderPortRef returned nil result");
  1369.             
  1370.         OTCloseProvider(atref);
  1371.     }
  1372.     else
  1373.         fprintf(stdout, "\n OTOpenAppleTalkServices returned error %d", err);
  1374.         
  1375.  
  1376. }
  1377.  
  1378. void ListEnetDrivers(void)
  1379. {
  1380.     OSStatus        osStatus;
  1381.     OTPortRecord    portRecord;
  1382.     Boolean            foundAPort;
  1383.     UInt32            index;
  1384.     Str255            userFriendlyName;
  1385.     
  1386.     fprintf(stdout, "\n The list of drivers present is:\n");        
  1387.     index = 0;
  1388.         // iterate thru each OT port record for ethernet ports.    
  1389.     while (foundAPort = OTGetIndexedPort(&portRecord,index))
  1390.     {
  1391.         if ((portRecord.fCapabilities & kOTPortIsDLPI) &&
  1392.             (portRecord.fCapabilities & kOTPortIsTPI) &&
  1393.             (kOTEthernetDevice == OTGetDeviceTypeFromPortRef(portRecord.fRef)))
  1394.         {
  1395.             OTGetUserPortNameFromPortRef(portRecord.fRef, userFriendlyName);
  1396.             fprintf(stdout, "\n Driver name - %s, ", portRecord.fPortName);
  1397.             fprintf(stdout, "user readable name is - %#s", userFriendlyName);
  1398.                 
  1399.         }
  1400.         index++;
  1401.     }
  1402.     fprintf(stdout, "\n");    
  1403.     
  1404. }
  1405.